/*
 * Copyright 2011 J. Auer, J. Andert, F.-J. Jendrusch, U. Celebi
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package de.fuberlin.replication.notepad;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.SQLException;

import com.example.android.notepad.Note;

import de.fuberlin.replication.Replication;
import de.fuberlin.replication.application.SynchronizableAbstract;
import de.fuberlin.replication.communication.Communication;
import de.fuberlin.replication.communication.wifi.java.net.JavaNetWiFiCommunication;
import de.fuberlin.replication.logging.Logger;
import de.fuberlin.replication.logging.defaultjava.DefaultLogger;
import de.fuberlin.replication.notepad.db.NotesDAO;
import de.fuberlin.replication.notepad.db.NotesDatabase;
import de.fuberlin.replication.storage.Storage;
import de.fuberlin.replication.storage.jdbc.sqlite.SQLiteStorage;

/**
 * This is a simple text UI for messing around with the notes.
 */
public class NotesPad extends SynchronizableAbstract {
	/**
	 * Data access object (DAO) for the notes.
	 */
	protected NotesDAO notesDAO;
	/**
	 * Address of this device for ID.
	 */
	protected String address;

	/**
	 * WiFi communication.
	 */
	protected JavaNetWiFiCommunication communication = new JavaNetWiFiCommunication();

	/**
	 * Default <code>System.out</code> logger.
	 */
	protected DefaultLogger logger;

	/**
	 * SQLite for storage of meta data.
	 */
	protected SQLiteStorage storage;

	/**
	 * @param notesDAO The notes DAO for accessing the notes
	 * @param address A customized string, used for identifying this replica
	 */
	public NotesPad(NotesDAO notesDAO, String address) {
		this.notesDAO = notesDAO;
		this.address = address;
	}

	/**
	 * @param notesDAO The notes DAO for accessing the notes
	 */
	public NotesPad(NotesDAO notesDAO) {
		this.notesDAO = notesDAO;
		address = "PC";
	}

	private void menu() {
		System.out.println("  + L .......... List of notes");
		System.out.println("  + C .......... Create new note");
		System.out.println("  + E \"title\"... Edit note #title");
		System.out.println("  + D \"title\"... Delete note #title ('all' for all)");
		System.out.println("  + S........... Synchronize");
		System.out.println("  + Q .......... QUIT");
	}

	/**
	 * List notes in database.
	 * 
	 * @throws SQLException If couldn't read notes from database
	 */
	public void list() throws SQLException {
		// Iterate D all notes
		Iterable<Note> notes = notesDAO.getAll();
		for (Note n : notes)
			System.out.printf("  + TITLE: %-15s NOTE: %-30s\n", n.getTitle(), n.getNote());
	}

	/**
	 * Delete note.
	 * 
	 * @param title Title of note to delete
	 * @throws SQLException If couldn't delete note
	 */
	public void delete(String title) throws SQLException {
		System.out.println(" DELETING note " + title + "...");
		Replication.update(this, title);
		notesDAO.delete(title);
		System.out.println("done.");
	}

	/**
	 * Create a new note.
	 * 
	 * @param input BufferedReader for reading user input.
	 * @throws IOException If couldn't read from input stream
	 * @throws SQLException If coulnd't create note in DB
	 */
	public void create(BufferedReader input) throws IOException, SQLException {
		System.out.println("\n CREATE new note...");
		System.out.println("\n Please give a title for the note: ");
		String title = input.readLine();
		System.out.println("\n Please give a text for the note: ");
		String note = input.readLine();
		System.out.print("\n Creating new note... ");
		notesDAO.set(new Note(title, note));
		Replication.update(this, title);
		System.out.println("done.");
	}

	/**
	 * Edit a note given by its title.
	 * 
	 * @param input BufferedReader for reading user input.
	 * @param title Title of the note to be edited
	 * @throws IOException If couldn't read from input stream
	 * @throws SQLException If coulnd't create note in DB
	 */
	public void edit(BufferedReader input, String title) throws IOException, SQLException {
		Note n = notesDAO.get(title);

		System.out.println("\n EDIT note " + title + "...");
		System.out.println("\n Please give a title for the note: ");
		String newTitle = input.readLine();
		System.out.println("\n The old text is: " + n.getNote());
		System.out.println("\n Please give a text for the note: ");
		String note = input.readLine();

		System.out.print("\n Editing note...");
		n.setTitle(newTitle);
		n.setNote(note);

		notesDAO.edit(title, n);
		Replication.update(this, title);
		System.out.println("done.");
	}

	private void synchronize(BufferedReader input) throws IOException {
		System.out.println("\n Enter IP address to connect to, or 'l' to listen:");
		String line = input.readLine();

		if (line.equals("l"))
			communication.listen(60000);
		else
			communication.connect(line, 60000);

		Replication.synchronize(this);
	}

	/**
	 * This method contains a simple UI.
	 * 
	 * @param args Calling arguments for the program
	 * @throws Exception If an error occurs
	 */
	public static void main(String[] args) throws Exception {
		// Open DB connection
		NotesDatabase db = new NotesDatabase();
		db.open();
		// DAO for accessing notes
		NotesDAO notesDAO = new NotesDAO(db.getConnection());
		// NotesList main programm
		NotesPad nl = new NotesPad(notesDAO);

		BufferedReader lineOfText = new BufferedReader(new InputStreamReader(System.in));
		String input = "";
		do {
			nl.menu();
			System.out.println();
			if (input.equalsIgnoreCase("L"))
				nl.list();
			else if (input.equalsIgnoreCase("C"))
				nl.create(lineOfText);
			else if (input.startsWith("E "))
				nl.edit(lineOfText, input.substring(2));
			else if (input.startsWith("D "))
				nl.delete(input.substring(2));
			else if (input.equalsIgnoreCase("S"))
				nl.synchronize(lineOfText);
			
			System.out.println();
		} while (!(input = lineOfText.readLine()).equals("Q"));

		db.close();
	}

	@Override
	public String getAddress() {
		return address;
	}

	@Override
	public Communication getCommunication() {
		if (communication == null)
			communication = new JavaNetWiFiCommunication();

		return communication;
	}

	@Override
	public Logger getLogger() {
		if (logger == null)
			logger = new DefaultLogger();

		return logger;
	}

	@Override
	public Object getObject(String arg0) {
		try {
			return notesDAO.get(arg0);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public Storage getStorage() {
		if (storage == null)
			storage = new SQLiteStorage();

		return storage;
	}

	@Override
	public void putObject(String arg0, Object arg1) {
		try {
			notesDAO.set(arg0, ((Note) arg1).getNote());
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}